import json
import csv
import dicttoxml
import pickle
import re
from datetime import datetime

# 抽象类
from abc import ABC, abstractmethod


# 定义抽象类 Person
class Person(ABC):
    def __init__(self, name, pid):
        self._name = name  # 保护成员
        self.__pid = pid  # 私有成员

    @property#可读
    def name(self):
        return self._name

    @name.setter#可写
    def name(self, value):
        self._name = value

    @property
    def pid(self):
        return self.__pid

    @abstractmethod
    def display_info(self):
        pass


# 学生类
class Student(Person):
    def __init__(self, name, stuid, gender, ethnicity, class_info, major,phone_number):
        super().__init__(name, stuid)
        self._gender = gender
        self._ethnicity = ethnicity
        self._class = class_info
        self._major = major
        self._dormitory = None

    @property
    def gender(self):
        return self._gender

    @property
    def ethnicity(self):
        return self._ethnicity

    @property
    def class_info(self):
        return self._class_info

    @property
    def major(self):
        return self._major

    @property
    def dormitory(self):
        return self._dormitory

    @dormitory.setter
    def dormitory(self, value):
        self._dormitory = value


    def to_dict(self):  # 对象序列化为字典
        return {
            "student_id": self.stuid,
            "name": self.name,
            "gender": self.gender,
            "ethnicity": self.ethnicity,
            "class_info": self.class_info,
            "phone_number": self.phone_number
        }


# 宿舍类
class Dormitory:
    def __init__(self, dorm_id, capacity, gender):
        self._dorm_id = dorm_id
        self._capacity = capacity
        self._gender = gender
        self._students = []

    @property
    def dorm_id(self):
        return self._dorm_id

    @property
    def capacity(self):
        return self._capacity

    @property
    def gender(self):
        return self._gender

    @property
    def students(self):
        return self._students

    def add_student(self, student):
        if len(self._students) < self._capacity and student.gender == self._gender:
            # 检查宿舍内是否全是一个民族
            ethnicities = [s.ethnicity for s in self._students]
            if ethnicities.count(student.ethnicity) == len(ethnicities):
                print("不能将该学生分配到该宿舍，宿舍内不能全是一个民族。")
                return False
            self._students.append(student)
            student.dormitory = self
            return True
        else:
            print("该宿舍已满或性别不符，无法分配。")
            return False

    def remove_student(self, student):
        if student in self._students:
            self._students.remove(student)
            student.dormitory = None
            return True
        return False

    def display_info(self):
        print(f"宿舍号: {self._dorm_id}, 容量: {self._capacity}, 性别: {self._gender}")
        for student in self._students:
            student.display_info()


# 管理员类
class Administrator(Person):
    def __init__(self, name, opid):
        super().__init__(name, opid)




    def add_student(self, students, dormitories, log_file):
        while True:
            try:
                name = input("学生姓名：")
                stuid = input("学号（4位数字）：")
                try:
                    if not re.match(r'^\d{4}$', stuid):
                        print("学号必须是4位数字，请重新输入。")
                        continue
                gender_choice = input("性别：1、男  2、女 （输入1，2）：")
                if gender_choice == '1':
                    gender = '男'
                elif gender_choice == '2':
                    gender = '女'
                else:
                    print("输入无效，请重新输入。")
                    continue
                ethnicity_choice = input("民族：1、汉  2、维吾尔 、3、哈萨克 7、其他（输入1，2…7）：")
                ethnicities = {
                    '1': '汉',
                    '2': '维吾尔',
                    '3': '哈萨克',
                    '7': '其他'
                }
                if ethnicity_choice not in ethnicities:
                    print("输入无效，请重新输入。")
                    continue
                ethnicity = ethnicities[ethnicity_choice]
                class_info = input("班级：")
                major = input("专业：")
                student = Student(name, stuid, gender, ethnicity, class_info, major)
                students.append(student)
                create_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                self._log_operation(log_file, f"添加学生(Stuid:{stuid})", create_time)
                self._save_data(students, dormitories)
                print("学生信息添加成功。")
                break
            except Exception as e:
                print(f"发生错误: {e}，请重新输入。")

    def modify_student(self, students, dormitories, log_file):
        stuid = input("请输入要修改的学生学号：")
        for student in students:
            if student.pid == stuid:
                try:
                    name = input(f"新姓名（原姓名: {student.name}）：")
                    if name:
                        student.name = name
                    gender_choice = input(f"新性别（原性别: {student.gender}）：1、男  2、女 （输入1，2）：")
                    if gender_choice == '1':
                        student._gender = '男'
                    elif gender_choice == '2':
                        student._gender = '女'
                    ethnicity_choice = input(
                        f"新民族（原民族: {student.ethnicity}）：1、汉  2、维吾尔 、3、哈萨克 7、其他（输入1，2…7）：")
                    ethnicities = {
                        '1': '汉',
                        '2': '维吾尔',
                        '3': '哈萨克',
                        '7': '其他'
                    }
                    if ethnicity_choice in ethnicities:
                        student._ethnicity = ethnicities[ethnicity_choice]
                    class_info = input(f"新班级（原班级: {student.class_info}）：")
                    if class_info:
                        student._class_info = class_info
                    major = input(f"新专业（原专业: {student.major}）：")
                    if major:
                        student._major = major
                    create_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                    self._log_operation(log_file, f"修改学生信息(Stuid:{stuid})", create_time)
                    self._save_data(students, dormitories)
                    print("学生信息修改成功。")
                    return
                except Exception as e:
                    print(f"发生错误: {e}，请重新输入。")
        print("未找到该学生信息。")

    def delete_student(self, students, dormitories, log_file):
        stuid = input("请输入要删除的学生学号：")
        for student in students:
            if student.pid == stuid:
                if student.dormitory:
                    student.dormitory.remove_student(student)
                students.remove(student)
                create_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                self._log_operation(log_file, f"删除学生(Stuid:{stuid})", create_time)
                self._save_data(students, dormitories)
                print("学生信息删除成功。")
                return
        print("未找到该学生信息。")

    def add_dormitory(self, students, dormitories, log_file):
        try:
            dorm_id = input("宿舍号：")
            capacity_choice = input("宿舍容量：2、2人间  4、4人间  6、6人间 （输入2，4，6）：")
            if capacity_choice not in ['2', '4', '6']:
                print("输入无效，请重新输入。")
                return
            capacity = int(capacity_choice)
            gender_choice = input("性别：1、男  2、女 （输入1，2）：")
            if gender_choice == '1':
                gender = '男'
            elif gender_choice == '2':
                gender = '女'
            else:
                print("输入无效，请重新输入。")
                return
            dormitory = Dormitory(dorm_id, capacity, gender)
            dormitories.append(dormitory)
            create_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            self._log_operation(log_file, f"添加宿舍(Dormid:{dorm_id})", create_time)
            self._save_data(students, dormitories)
            print("宿舍信息添加成功。")
        except Exception as e:
            print(f"发生错误: {e}，请重新输入。")

    def modify_dormitory(self, students, dormitories, log_file):
        dorm_id = input("请输入要修改的宿舍号：")
        for dormitory in dormitories:
            if dormitory.dorm_id == dorm_id:
                try:
                    capacity_choice = input(
                        f"新容量（原容量: {dormitory.capacity}）：2、2人间  4、4人间  6、6人间 （输入2，4，6）：")
                    if capacity_choice in ['2', '4', '6']:
                        dormitory._capacity = int(capacity_choice)
                    gender_choice = input(f"新性别（原性别: {dormitory.gender}）：1、男  2、女 （输入1，2）：")
                    if gender_choice == '1':
                        dormitory._gender = '男'
                    elif gender_choice == '2':
                        dormitory._gender = '女'
                    create_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                    self._log_operation(log_file, f"修改宿舍信息(Dormid:{dorm_id})", create_time)
                    self._save_data(students, dormitories)
                    print("宿舍信息修改成功。")
                    return
                except Exception as e:
                    print(f"发生错误: {e}，请重新输入。")
        print("未找到该宿舍信息。")

    def delete_dormitory(self, students, dormitories, log_file):
        dorm_id = input("请输入要删除的宿舍号：")
        for dormitory in dormitories:
            if dormitory.dorm_id == dorm_id:
                for student in dormitory.students:
                    student.dormitory = None
                dormitories.remove(dormitory)
                create_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                self._log_operation(log_file, f"删除宿舍(Dormid:{dorm_id})", create_time)
                self._save_data(students, dormitories)
                print("宿舍信息删除成功。")
                return
        print("未找到该宿舍信息。")

    def allocate_dormitory(self, students, dormitories, log_file):
        stuid = input("请输入要分配宿舍的学生学号：")
        for student in students:
            if student.pid == stuid:
                dorm_id = input("请输入要分配的宿舍号：")
                for dormitory in dormitories:
                    if dormitory.dorm_id == dorm_id:
                        if dormitory.add_student(student):
                            create_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
                            self._log_operation(log_file, f"分配宿舍(Stuid:{stuid}, Dormid:{dorm_id})", create_time)
                            self._save_data(students, dormitories)
                            print("宿舍分配成功。")
                        return
                print("未找到该宿舍信息或无法分配。")
                return
        print("未找到该学生信息。")

    def _log_operation(self, log_file, operation, create_time):
        log_id = len(log_file) + 1
        log_entry = f"Logid {log_id},opname:{operation} ,operator:{self.name} ,op_time: {create_time}"
        log_file.append(log_entry)
        with open('log.txt', 'a', encoding='utf-8') as f:
            f.write(log_entry + '\n')

    def _save_data(self, students, dormitories):
        # 保存为JSON
        student_data = [
            {
                "Opid": self.pid,
                "Stuid": student.pid,
                "stuname": student.name,
                "gender": student.gender,
                "ethnicity": student.ethnicity,
                "class_info": student.class_info,
                "major": student.major,
                "dormitory": student.dormitory.dorm_id if student.dormitory else None,
                "creat_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            }
            for student in students
        ]
        with open('students.json', 'w', encoding='utf-8') as f:
            json.dump(student_data, f, ensure_ascii=False, indent=4)

        dormitory_data = [
            {
                "Opid": self.pid,
                "Dormid": dormitory.dorm_id,
                "capacity": dormitory.capacity,
                "gender": dormitory.gender,
                "students": [student.pid for student in dormitory.students],
                "creat_time": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            }
            for dormitory in dormitories
        ]
        with open('dormitories.json', 'w', encoding='utf-8') as f:
            json.dump(dormitory_data, f, ensure_ascii=False, indent=4)

        # 保存为CSV
        with open('students.csv', 'w', newline='', encoding='utf-8') as f:
            fieldnames = ["Opid", "Stuid", "stuname", "gender", "ethnicity", "class_info", "major", "dormitory",
                          "creat_time"]
            writer = csv.DictWriter(f, fieldnames=fieldnames)
            writer.writeheader()
            for student in student_data:
                writer.writerow(student)

        with open('dormitories.csv', 'w', newline='', encoding='utf-8') as f:
            fieldnames = ["Opid", "Dormid", "capacity", "gender", "students", "creat_time"]
            writer = csv.DictWriter(f, fieldnames=fieldnames)
            writer.writeheader()
            for dormitory in dormitory_data:
                writer.writerow(dormitory)

        # 保存为XML
        students_xml = ET.Element('students')
        for student in student_data:
            student_xml = ET.SubElement(students_xml, 'student')
            for key, value in student.items():
                ET.SubElement(student_xml, key).text = str(value)
        tree = ET.ElementTree(students_xml)
        tree.write('students.xml', encoding='utf-8', xml_declaration=True)

        dormitories_xml = ET.Element('dormitories')
        for dormitory in dormitory_data:
            dormitory_xml = ET.SubElement(dormitories_xml, 'dormitory')
            for key, value in dormitory.items():
                ET.SubElement(dormitory_xml, key).text = str(value)
        tree = ET.ElementTree(dormitories_xml)
        tree.write('dormitories.xml', encoding='utf-8', xml_declaration=True)

        # 保存为二进制
        data = {
            "students": student_data,
            "dormitories": dormitory_data
        }
        with open('data.pickle', 'wb') as f:
            pickle.dump(data, f)

    def display_info(self):
        print(f"管理员姓名: {self._name}, 操作员ID: {self.pid}")


# 教师类
class Teacher(Person):
    def __init__(self, name, tid):
        super().__init__(name, tid)

    def query_student_dormitory(self, students):
        stuid = input("请输入要查询的学生学号：")
        for student in students:
            if student.pid == stuid:
                dorm_info = student.dormitory.dorm_id if student.dormitory else "未分配"
                print(f"学生姓名: {student.name}, 学号: {student.pid}, 宿舍号: {dorm_info}")
                return
        print("未找到该学生信息。")

    def display_info(self):
        print(f"教师姓名: {self._name}, 教师ID: {self.pid}")


# 辅导员类，多继承
class Counselor(Administrator, Teacher):
    def __init__(self, name, cid):
        super().__init__(name, cid)

    def display_info(self):
        print(f"辅导员姓名: {self._name}, 辅导员ID: {self.pid}")


# 主程序
def main():
    students = []
    dormitories = []
    log_file = []
    administrator = Administrator("管理员", "1001")

    while True:
        print("请选择操作：")
        print("1、学生信息管理   2、宿舍信息管理   3、宿舍分配  4、教师查询  5、退出")
        choice = input("输入 1….5 然后回车进入对应的功能：")

        if choice == '1':
            print("1、添加学生    2、修改学生信息   3、删除学生   4、查询")
            sub_choice = input("请选择操作：")
            if sub_choice == '1':
                administrator.add_student(students, dormitories, log_file)
            elif sub_choice == '2':
                administrator.modify_student(students, dormitories, log_file)
            elif sub_choice == '3':
                administrator.delete_student(students, dormitories, log_file)
            elif sub_choice == '4':
                for student in students:
                    student.display_info()
            else:
                print("输入无效，请重新输入。")
        elif choice == '2':
            print("1、添加宿舍    2、修改宿舍信息   3、删除宿舍   4、查询")
            sub_choice = input("请选择操作：")
            if sub_choice == '1':
                administrator.add_dormitory(students, dormitories, log_file)
            elif sub_choice == '2':
                administrator.modify_dormitory(students, dormitories, log_file)
            elif sub_choice == '3':
                administrator.delete_dormitory(students, dormitories, log_file)
            elif sub_choice == '4':
                for dormitory in dormitories:
                    dormitory.display_info()
            else:
                print("输入无效，请重新输入。")
        elif choice == '3':
            administrator.allocate_dormitory(students, dormitories, log_file)
        elif choice == '4':
            teacher = Teacher("教师", "2001")
            teacher.query_student_dormitory(students)
        elif choice == '5':
            break
        else:
            print("输入无效，请重新输入。")


if __name__ == "__main__":
    main()
